Imports System.Drawing
Imports System.Drawing.Drawing2D

'// this is a "ToolBar" control governed by graphics. Sweetness. The background is a region, and each button is a region as well.
'// Buttons are drawn all cool like... xxP

'// when mousing over it will change the text to yella
'// when turned on (for three state) ... dunno
'// when disabled, it will be gainsboro?

<Serializable()> Public Class cButton
    Public Event MouseChanged()

    Protected _buttonSize As New Size(42, 20)
    Protected _fontStyle As String = "cambria"
    Protected _location As New Point(0, 0)

    Protected _enabled As Boolean = False

    Protected _colorProperties As New cButtonColorProperties

    Protected _text As String = "STANDARD"
    Protected _textSize As Single = 12

    Protected _reg As Region
    Protected rect As Rectangle
    <NonSerialized()> Protected textPath As GraphicsPath
    <NonSerialized()> Protected borderPath As GraphicsPath

    Protected mouseIn As Boolean


    Public Sub init(ByVal buttonsize As Size, ByVal buttonlocation As Point, ByVal text As String)
        _buttonSize = buttonsize
        _location = buttonlocation
        _text = text

        rect = New Rectangle(_location.X, _location.Y, _buttonSize.Width, _buttonSize.Height)

        '// create text path
        CreateTextPath()

        '// border path
        borderPath = New GraphicsPath
        borderPath.AddLine(New PointF(_location.X, _location.Y + 3), New Point(_location.X + 3, _location.Y))
        borderPath.AddLine(New Point(_location.X + 3, _location.Y), New PointF(_location.X + _buttonSize.Width - 3, _location.Y))
        borderPath.AddLine(New PointF(_location.X + _buttonSize.Width - 3, _location.Y), New PointF(_location.X + _buttonSize.Width, _location.Y + 3))
        borderPath.AddLine(New PointF(_location.X + _buttonSize.Width, _location.Y + 3), New PointF(_location.X + _buttonSize.Width, _location.Y + _buttonSize.Height - 3))
        borderPath.AddLine(New PointF(_location.X + _buttonSize.Width, _location.Y + _buttonSize.Height - 3), New PointF(_location.X + _buttonSize.Width - 3, _location.Y + _buttonSize.Height))
        borderPath.AddLine(New PointF(_location.X + _buttonSize.Width - 3, _location.Y + _buttonSize.Height), New PointF(_location.X + 3, _location.Y + _buttonSize.Height))
        borderPath.AddLine(New PointF(_location.X + 3, _location.Y + _buttonSize.Height), New PointF(_location.X, _location.Y + _buttonSize.Height - 3))
        borderPath.AddLine(New PointF(_location.X, _location.Y + _buttonSize.Height - 3), New PointF(_location.X, _location.Y + 3))
        borderPath.CloseFigure()

        borderPath.Reverse()

        _reg = New Region
        _reg.Intersect(rect)

    End Sub

    Private Sub CreateTextPath()
        '// create the region
        Dim fnt As New Font(_fontStyle, _textSize)

        '// generate the bound of the text (important for positioning)
        textPath = New GraphicsPath

        Dim pnt As New PointF(_location.X, _location.Y)
        textPath.AddString(_text, fnt.FontFamily, System.Drawing.FontStyle.Regular, fnt.Size, pnt, System.Drawing.StringFormat.GenericDefault)
        Dim bounds As RectangleF = textPath.GetBounds
        Dim offset As New Point((_buttonSize.Width / 2 - bounds.Size.Width / 2), _buttonSize.Height / 2 - bounds.Size.Height / 2)

        offset.X -= 3
        offset.Y = 6

        Dim mat As New Matrix()
        mat.TransformPoints(textPath.PathPoints) '// all points are transformed
        mat.Translate(offset.X, offset.Y)
        textPath.Transform(mat)
    End Sub

    Public Property colorProperties() As cButtonColorProperties
        Get
            Return _colorProperties
        End Get
        Set(ByVal value As cButtonColorProperties)
            _colorProperties = value
        End Set
    End Property

    Public Property Text() As String
        Get
            Return _text
        End Get
        Set(ByVal value As String)
            _text = value
            CreateTextPath()
        End Set
    End Property

    Public Property Enabled() As Boolean
        Get
            Return _enabled
        End Get
        Set(ByVal value As Boolean)
            _enabled = value
        End Set
    End Property

    Public Sub MouseOut()
        '// the mouse is moved OFF the parent control
        If _enabled = False Then Exit Sub

        If mouseIn = True Then
            mouseIn = False
            RaiseEvent MouseChanged()
        End If
    End Sub

    Public Overridable Sub DrawButton(ByRef g As Graphics)
        Try

            If _enabled = True Then
                If mouseIn Then
                    g.FillPath(New LinearGradientBrush(_location, New Point(_location.X + _buttonSize.Width, +_location.Y + _buttonSize.Height), _colorProperties.mouseovercolor1, _colorProperties.mouseovercolor2), borderPath)
                Else
                    g.FillPath(New LinearGradientBrush(_location, New Point(_location.X + _buttonSize.Width, +_location.Y + _buttonSize.Height), _colorProperties.backColor1, _colorProperties.backColor2), borderPath)
                End If

                g.SmoothingMode = SmoothingMode.AntiAlias
                g.DrawPath(_colorProperties.BorderPen, borderPath)
                g.DrawPath(New Pen(_colorProperties.TextColor), textPath)
            Else

                g.FillPath(Brushes.DarkGray, borderPath)

                g.SmoothingMode = SmoothingMode.AntiAlias
                g.DrawPath(_colorProperties.BorderPen, borderPath)
                g.DrawPath(New Pen(_colorProperties.TextColor), textPath)
            End If

        Catch ex As Exception
            Debug.WriteLine("Error in draw")
        End Try

    End Sub

    Public Sub MouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)

        If _enabled = False Then Exit Sub

        If (e.X > rect.Left) AndAlso (e.X < rect.Right) Then
            If (e.Y > rect.Top) AndAlso (e.Y < rect.Bottom) Then
                If mouseIn = True Then Exit Sub
                mouseIn = True
                RaiseEvent MouseChanged()
            Else
                If mouseIn = False Then Exit Sub
                mouseIn = False
                RaiseEvent MouseChanged()
            End If

        Else
            If mouseIn = False Then Exit Sub
            mouseIn = False
            RaiseEvent MouseChanged()
        End If
    End Sub

    Public Overridable Function MouseClickIn(ByVal e As System.Windows.Forms.MouseEventArgs) As Boolean
        If _enabled = False Then Exit Function

        If (e.X > rect.Left) AndAlso (e.X < rect.Right) Then
            If (e.Y > rect.Top) AndAlso (e.Y < rect.Bottom) Then
                MouseOut()
                Return True
            End If
        End If
        Return False
    End Function

    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub
End Class

<Serializable()> Public Class cButtonToggle : Inherits cButton
    Private _checked As Boolean = False

    Private _uncheckedColor As New cButtonColorProperties

    Public Property uncheckedColor() As cButtonColorProperties
        Get
            Return _uncheckedColor
        End Get
        Set(ByVal value As cButtonColorProperties)
            _uncheckedColor = value
        End Set
    End Property

    Public Property checked() As Boolean
        Get
            Return _checked
        End Get
        Set(ByVal value As Boolean)
            _checked = value

        End Set
    End Property

    Public Overrides Sub DrawButton(ByRef g As System.Drawing.Graphics)
        If _checked = True Then MyBase.DrawButton(g)

        '// if we're unchecked, we use the unchecked color
        Try

            If _enabled = True Then
                If mouseIn Then
                    g.FillPath(New LinearGradientBrush(_location, New Point(_location.X + _buttonSize.Width, +_location.Y + _buttonSize.Height), _uncheckedColor.mouseovercolor1, _uncheckedColor.mouseovercolor2), borderPath)
                Else
                    If _checked = True Then
                        g.FillPath(New LinearGradientBrush(_location, New Point(_location.X + _buttonSize.Width, +_location.Y + _buttonSize.Height), Color.Green, Color.DarkSeaGreen), borderPath)
                    Else
                        g.FillPath(New LinearGradientBrush(_location, New Point(_location.X + _buttonSize.Width, +_location.Y + _buttonSize.Height), _uncheckedColor.backColor1, _uncheckedColor.backColor2), borderPath)
                    End If

                End If

                g.SmoothingMode = SmoothingMode.AntiAlias
                g.DrawPath(_colorProperties.BorderPen, borderPath)
                g.DrawPath(New Pen(_colorProperties.TextColor), textPath)
            Else

                g.FillPath(Brushes.DarkGray, borderPath)

                g.SmoothingMode = SmoothingMode.AntiAlias
                g.DrawPath(_colorProperties.BorderPen, borderPath)
                g.DrawPath(New Pen(_colorProperties.TextColor), textPath)
            End If

        Catch ex As Exception
            Debug.WriteLine("Error in draw")
        End Try
    End Sub

End Class

<Serializable()> Public Class cButtonColorProperties
    Private _backColor1 As Color = Color.SteelBlue
    Private _backColor2 As Color = Color.LightSteelBlue

    Private _mouseOverColor1 As Color = Color.Goldenrod
    Private _mouseovercolor2 As Color = Color.LightYellow

    Private _textColor As Color = Color.Black

    Private _borderPen As New Pen(Color.Black, 2)

    Public Property BorderPen() As Pen
        Get
            Return _borderPen
        End Get
        Set(ByVal value As Pen)
            _borderPen = value
        End Set
    End Property

    Public Property backColor1() As Color
        Get
            Return _backColor1
        End Get
        Set(ByVal value As Color)
            _backColor1 = value
        End Set
    End Property

    Public Property backColor2() As Color
        Get
            Return _backColor2
        End Get
        Set(ByVal value As Color)
            _backColor2 = value
        End Set
    End Property

    Public Property mouseovercolor1() As Color
        Get
            Return _mouseOverColor1
        End Get
        Set(ByVal value As Color)
            _mouseOverColor1 = value
        End Set
    End Property

    Public Property mouseovercolor2() As Color
        Get
            Return _mouseovercolor2
        End Get
        Set(ByVal value As Color)
            _mouseovercolor2 = value
        End Set
    End Property

    Public Property TextColor() As Color
        Get
            Return _textColor
        End Get
        Set(ByVal value As Color)
            _textColor = value
        End Set
    End Property

    Protected Overrides Sub Finalize()
        _borderPen.Dispose()
        MyBase.Finalize()
    End Sub
End Class